C++指针详解

您所在的位置:网站首页 c++ 指针的数据类型 C++指针详解

C++指针详解

2023-07-16 17:21| 来源: 网络整理| 查看: 265

概述

C/C++语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是C/C++语言的灵魂一点都不为过。 有好的一面,必然会有坏的一面,指针的灵活导致了它的难以控制,所以C/C++程序员的很多bug是基于指针问题上的。今天就对指针进行详细的整理。

1、指针是什么?

指针是“指向(point to)”另外一种类型的复合类型。复合类型是指基于其它类型定义的类型。

理解指针,先从内存说起:内存是一个很大的,线性的字节数组。每一个字节都是固定的大小,由8个二进制位组成。最关键的是,每一个字节都有一个唯一的编号,编号从0开始,一直到最后一个字节。

程序加载到内存中后,在程序中使用的变量、常量、函数等数据,都有自己唯一的一个编号,这个编号就是这个数据的地址。

指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们一般用16进制表示。指针的值(虚拟地址值)使用一个机器字的大小来存储,也就是说,对于一个机器字为w位的电脑而言,它的虚拟地址空间是0~[2的w次幂] - 1,程序最多能访问2的w次幂个字节。这就是为什么xp这种32位系统最大支持4GB内存的原因了。 在这里插入图片描述

因此可以理解为:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。

2、变量在内存中的存储

举一个最简单的例子 int a = 1,假设计算机使用大端方式存储: 在这里插入图片描述 内存数据有几点规律:

计算机中的所有数据都是以二进制存储的数据类型决定了占用内存的大小占据内存的地址就是地址值最小的那个字节的地址。

现在就可以理解 a 在内存中为什么占4个字节,而且首地址为0028FF40了。

3、指针对象(变量)

用来保存指针的对象,就是指针对象。如果指针变量p1保存了变量 a 的地址,则就说:p1指向了变量a,也可以说p1指向了a所在的内存块 ,这种指向关系,在图中一般用 箭头表示: 在这里插入图片描述 指针对象p1,也有自己的内存空间,32位机器占4个字节,64位机器占8个字节。所以会有指针的指针。

3.1、定义指针对象

定义指针变量时,在变量名前写一个 * 星号,这个变量就变成了对应变量类型的指针变量。必要时要加( ) 来避免优先级的问题:

int* p_int; //指向int类型变量的指针 double* p_double; //指向double类型变量的指针 Student* p_struct; //类或结构体类型的指针 int** p_pointer; //指向 一个整形变量指针的指针 int(*p_arr)[3]; //指向含有3个int元素的数组的指针 int(*p_func)(int,int); //指向返回类型为int,有2个int形参的函数的指针 3.2、获取对象地址

指针用于存放某个对象的地址,要想获取该地址,虚使用取地址符(&),如下:

int add(int a , int b) { return a + b; } int main(void) { int num = 97; float score = 10.00F; int arr[3] = {1,2,3}; int* p_num = # int* p_arr1 = arr; //p_arr1意思是指向数组第一个元素的指针 float* p_score = &score; int (*p_arr)[3] = &arr; int (*fp_add)(int ,int ) = add; //p_add是指向函数add的函数指针 const char* p_msg = "Hello world";//p_msg是指向字符数组的指针 return 0; }

通过上面可以看到&的使用,但是有几个例子没有使用&,因为这是特殊情况:

数组名的值就是这个数组的第一个元素的地址。函数名的值就是这个函数的地址。字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称,也就是这个字符串在内存中的地址。 3.3、解析地址对象

如果指针指向了一个对象,则允许使用解引用符(*)来访问该对象,如下:

int age = 19; int* p_age = &age; *p_age = 20; //通过指针修改指向的内存数据 printf("age = %d\n",*p_age); //通过指针读取指向的内存数据 printf("age = %d\n",age);

对于结构体和类,两者的差别很小,所以几乎可以等同,则使用->符号访问内部成员:

struct Student { char name[31]; int age; float score; }; int main(void) { Student stu = {"Bob" , 19, 98.0}; Student* p_s = &stu; p_s->age = 20; p_s->score = 99.0; printf("name:%s age:%d\n",p_s->name,p_s->age); return 0; } 3.4、指针值的状态

指针的值(即地址)总会是下列四种状态之一:

指向一个对象的地址指向紧邻对象所占空间的下一个位置空指针,意味着指针没有指向任何对象无效指针(野指针),上述情况之外的其他值

第一种状态很好理解就不说明了,第二种状态主要用于迭代器和指针的计算,后面介绍指针的计算,迭代器等整理模板的时候在介绍。

空指针:在C语言中,我们让指针变量赋值为NULL表示一个空指针,而C语言中,NULL实质是 ((void*)0) , 在C++中,NULL实质是0。C++中也可以使用C11标准中的nullpte字面值赋值,意思是一样的。 任何程序数据都不会存储在地址为0的内存块中,它是被操作系统预留的内存块。

无效指针:指针变量的值是NULL,或者未知的地址值,或者是当前应用程序不可访问的地址值,这样的指针就是无效指针,不能对他们做解指针操作,否则程序会出现运行时错误,导致程序意外终止。

任何一个指针变量在做解地址操作前,都必须保证它指向的是有效的,可用的内存块,否则就会出错。坏指针是造成C语言Bug的最频繁的原因之一。

未经初始化的指针就是个无效指针,所以在定义指针变量的时候一定要进行初始化。如果实在是不知道指针的指向,则使用nullptr或NULL进行赋值。

3.5、指针之间的赋值

指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。

int* p1 = &a; int* p2 = p1;

在这里插入图片描述 p1和p2所在的内存地址不同,但是所指向的内存地址相同,都是0028FF40。

4、指针内含信息

通过上面的介绍,我们可以看出指针包含两部分信息:所指向的值和类型信息。

指针的值:这个就不说了,上面大部分都是这个介绍。 指针的类型信息:类型信息决定了这个指针指向的内存的字节数并如何解释这些字节信息。一般指针变量的类型要和它指向的数据的类型匹配。

同样的地址,因为指针的类型不同,对它指向的内存的解释就不同,得到的就是不同的数据。

char array1[20] = "abcdefghijklmnopqrs"; char* ptr1 = array1; int* ptr2 = (int*)ptr1; ptr1++; ptr2++; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3